<template>
  <div class="tag-input" :class="size && `tag-input--${size}`">
    <!-- 标签容器（带动画） -->
    <transition-group name="tag-list" tag="div" class="tag-container">
      <div
          v-for="(tag, index) in innerTags"
          :key="tag + index"
          class="tag-item"
          :style="tagStyle"
      >
        <!-- 可编辑标签 -->
        <span
            v-if="editingIndex !== index"
            @dblclick="handleEditTag(index)"
        >{{ tag }}</span>
        <input
            v-else
            v-model="editingValue"
            @keydown.enter="handleEditConfirm(index)"
            @blur="handleEditConfirm(index)"
            @keydown.esc="editingIndex = -1"
            class="tag-edit-input"
        />
        <!-- 删除按钮 -->
        <span @click="removeTag(index)" class="tag-remove">&times;</span>
      </div>
    </transition-group>

    <!-- 输入框 + 自动完成 -->
    <div class="input-wrapper">
      <input
          ref="inputRef"
          v-model="inputValue"
          :placeholder="filteredPlaceholder"
          :style="inputStyle"
          @keydown="handleKeydown"
          @input="handleInput"
          @focus="$emit('focus')"
          @blur="$emit('blur')"
          class="tag-input-field"
      />
      <transition name="fade">
        <div v-if="suggestionsVisible" class="suggestions">
          <div
              v-for="(suggestion, idx) in filteredSuggestions"
              :key="idx"
              @click="selectSuggestion(suggestion)"
              class="suggestion-item"
          >{{ suggestion }}</div>
        </div>
      </transition>
    </div>
  </div>
</template>

<script setup>
import { ref, computed, watch, nextTick } from 'vue'

const props = defineProps({
  modelValue: { type: Array, default: () => [] },
  tags: { type: Array, default: () => [] },
  maxTags: Number,
  minTags: Number,
  placeholder: { type: String, default: '输入标签...' },
  separator: { type: [String, Array], default: ',' },
  allowDuplicates: Boolean,
  size: String,
  inputStyle: [Object, String],
  tagStyle: [Object, String],
  pattern: [RegExp, String],
  maxLength: Number
})

const emit = defineEmits([
  'update:modelValue',
  'add',
  'remove',
  'input',
  'blur',
  'focus'
])

// 响应式数据
const inputRef = ref(null)
const inputValue = ref('')
const innerTags = ref([...props.modelValue.length ? props.modelValue : props.tags])
const editingIndex = ref(-1)
const editingValue = ref('')
const suggestionsVisible = ref(false)

// 计算属性
const filteredPlaceholder = computed(() => {
  if (props.maxTags && innerTags.value.length >= props.maxTags) {
    return '已达到最大标签数量'
  }
  return props.placeholder
})

const filteredSuggestions = computed(() => {
  // 实际项目中应从 props 接收建议数据，这里做简单演示
  const demoData = ['Vue', 'React', 'Angular', 'Svelte', 'JavaScript']
  return demoData.filter(item =>
      item.toLowerCase().includes(inputValue.value.toLowerCase())
  )
})

// 方法
const validateTag = (tag) => {
  tag = tag.trim()
  if (!tag) return false
  if (props.maxLength && tag.length > props.maxLength) return false
  if (props.pattern) {
    const pattern = typeof props.pattern === 'string'
        ? new RegExp(props.pattern)
        : props.pattern
    if (!pattern.test(tag)) return false
  }
  return true
}

const addTag = (tag) => {
  tag = tag.trim()
  if (!validateTag(tag)) return

  if (props.maxTags && innerTags.value.length >= props.maxTags) return
  if (!props.allowDuplicates && innerTags.value.includes(tag)) return

  innerTags.value.push(tag)
  emit('update:modelValue', [...innerTags.value])
  emit('add', tag)
}

const removeTag = (index) => {
  if (props.minTags && innerTags.value.length <= props.minTags) return
  const removed = innerTags.value.splice(index, 1)
  emit('update:modelValue', [...innerTags.value])
  emit('remove', removed[0])
}

const handleKeydown = (e) => {
  const separators = Array.isArray(props.separator)
      ? props.separator
      : [props.separator]

  if (e.key === 'Enter' || separators.includes(e.key)) {
    e.preventDefault()
    processInput()
  } else if (e.key === 'Backspace' && inputValue.value === '') {
    removeTag(innerTags.value.length - 1)
  }
}

const processInput = () => {
  const separators = Array.isArray(props.separator)
      ? props.separator.join('')
      : props.separator
  const splitRegExp = new RegExp(`[${separators}]`)

  inputValue.value.split(splitRegExp)
      .filter(t => t.trim())
      .forEach(t => addTag(t))

  inputValue.value = ''
}

const handleInput = () => {
  suggestionsVisible.value = inputValue.value.length > 0
  emit('input', inputValue.value)
}

const handleEditTag = async (index) => {
  editingIndex.value = index
  editingValue.value = innerTags.value[index]
  await nextTick()
  inputRef.value.focus()
}

const handleEditConfirm = (index) => {
  if (validateTag(editingValue.value)) {
    innerTags.value.splice(index, 1, editingValue.value.trim())
    emit('update:modelValue', [...innerTags.value])
  }
  editingIndex.value = -1
}

const selectSuggestion = (suggestion) => {
  addTag(suggestion)
  inputValue.value = ''
  suggestionsVisible.value = false
}

// 监听
watch(() => props.modelValue, (newVal) => {
  innerTags.value = [...newVal]
})
</script>

<style scoped>
.tag-input {
  border: 1px solid #ddd;
  padding: 8px;
  border-radius: 4px;
}

.tag-input--small { font-size: 12px }
.tag-input--medium { font-size: 14px }
.tag-input--large { font-size: 16px }

.tag-container {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-bottom: 8px;
}

.tag-item {
  background: #f0f0f0;
  padding: 4px 8px;
  border-radius: 12px;
  display: flex;
  align-items: center;
  gap: 4px;
}

.tag-remove {
  cursor: pointer;
  padding-left: 4px;
}

.tag-remove:hover {
  color: #f00;
}

.tag-edit-input {
  border: none;
  outline: none;
  background: transparent;
  font: inherit;
}

.input-wrapper {
  position: relative;
}

.suggestions {
  position: absolute;
  background: white;
  border: 1px solid #ddd;
  width: 100%;
  max-height: 200px;
  overflow-y: auto;
  z-index: 100;
}

.suggestion-item {
  padding: 8px;
  cursor: pointer;
}

.suggestion-item:hover {
  background: #f0f0f0;
}

/* 过渡动画 */
.tag-list-enter-active,
.tag-list-leave-active {
  transition: all 0.3s ease;
}
.tag-list-enter-from,
.tag-list-leave-to {
  opacity: 0;
  transform: translateY(10px);
}

.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.2s;
}
.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}
</style>